﻿using System;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.InteropServices;
using System.Text;

namespace Kyoh.Lib.Win32API.NetResources
{
    /// <summary>Win32 API。</summary>
    public static class NativeMethods
    {
        /// <summary>WNet メソッド群で発生した最後のエラーを取得します。</summary>
        /// <param name="error">エラーコード。</param>
        /// <param name="errorBuf">エラー情報バッファ。</param>
        /// <param name="errorBufSize">エラー情報バッファのサイズ。</param>
        /// <param name="lpNameBuf">エラー名称バッファ。</param>
        /// <param name="nameBufSize">エラー名称バッファのサイズ</param>
        /// <returns><see cref="WNetConnectionResult"/></returns>
        [DllImport("mpr.dll", EntryPoint = "WNetGetLastErrorW")]
        [CLSCompliant(false)]
        [SuppressMessage("Microsoft.Interoperability", "CA1401:PInvokesShouldNotBeVisible")]
        public static extern WNetConnectionResult WNetGetLastError(ref uint error, [MarshalAs(UnmanagedType.LPWStr)]StringBuilder errorBuf, uint errorBufSize, [MarshalAs(UnmanagedType.LPWStr)]StringBuilder lpNameBuf, uint nameBufSize);

        /// <summary>既存のネットワーク接続を切断します。また、記憶されているネットワーク接続で、現在接続が行われていないものを削除することもできます。</summary>
        /// <param name="name">リダイレクトされているローカルデバイス、または切断したいリモートネットワークリソースのどちらかの名前を表す文字列。</param>
        /// <param name="options">接続の種類。</param>
        /// <param name="force">強制的に切断するかどうか。</param>
        /// <returns><see cref="WNetConnectionResult"/></returns>
        [DllImport("mpr.dll", EntryPoint = "WNetCancelConnection2W", CharSet = CharSet.Unicode)]
        [CLSCompliant(false)]
        [SuppressMessage("Microsoft.Interoperability", "CA1401:PInvokesShouldNotBeVisible")]
        public static extern WNetConnectionResult WNetCancelConnection2([In, MarshalAs(UnmanagedType.LPWStr)]string name, ConnectionUpdateOptions options, [MarshalAs(UnmanagedType.Bool)]bool force);

        /// <summary>ローカル装置に対応するネットワークリソースの名前を取得します。</summary>
        /// <param name="localName">ローカル装置のドライブ名を表す文字列。</param>
        /// <param name="remoteName">ネットワークリソースの名前を取得する文字列バッファ。</param>
        /// <param name="length">文字列バッファのサイズ。バッファのサイズが不足して取得できなかった場合は、必要なバッファがこのパラメータに格納されます。</param>
        /// <returns><see cref="WNetConnectionResult"/></returns>
        [DllImport("mpr.dll", EntryPoint = "WNetGetConnectionW", CharSet = CharSet.Unicode)]
        [CLSCompliant(false)]
        [SuppressMessage("Microsoft.Interoperability", "CA1401:PInvokesShouldNotBeVisible")]
        public static extern WNetConnectionResult WNetGetConnection([In, MarshalAs(UnmanagedType.LPWStr)]string localName, [MarshalAs(UnmanagedType.LPWStr)]StringBuilder remoteName, ref uint length);

        /// <summary>現在の既定ユーザー名、またはネットワーク接続を確立するために使われるユーザー名を取得します。</summary>
        /// <param name="target">デバイスまたはリソース名</param>
        /// <param name="userName">名前バッファ。</param>
        /// <param name="bufferLength">バッファのサイズ。バッファのサイズが不足して取得できなかった場合は、必要なバッファがこのパラメータに格納されます。</param>
        /// <returns><see cref="WNetConnectionResult"/></returns>
        [DllImport("mpr.dll", EntryPoint = "WNetGetUserW", CharSet = CharSet.Unicode)]
        [CLSCompliant(false)]
        [SuppressMessage("Microsoft.Interoperability", "CA1401:PInvokesShouldNotBeVisible")]
        public static extern WNetConnectionResult WNetGetUser([In, MarshalAs(UnmanagedType.LPWStr)]string target, [MarshalAs(UnmanagedType.LPWStr)]StringBuilder userName, ref uint bufferLength);

        /// <summary>ネットワークリソースに接続します。</summary>
        /// <param name="owner">オーナーウィンドウハンドラ。IntPtr.Zero を使用できます。</param>
        /// <param name="netResource">接続の詳細。</param>
        /// <param name="password">パスワード。</param>
        /// <param name="userName">ユーザー名。</param>
        /// <param name="options">接続オプション。</param>
        /// <returns><see cref="WNetConnectionResult"/></returns>
        [DllImport("mpr.dll", EntryPoint = "WNetAddConnection3W", CharSet = CharSet.Unicode)]
        [CLSCompliant(false)]
        [SuppressMessage("Microsoft.Interoperability", "CA1401:PInvokesShouldNotBeVisible")]
        public static extern WNetConnectionResult WNetAddConnection3(IntPtr owner, ref NetResource netResource, [In, MarshalAs(UnmanagedType.LPWStr)]string password, [In, MarshalAs(UnmanagedType.LPWStr)]string userName, ConnectionUpdateOptions options);

        /// <summary>ネットワークリソースまたは現在の接続の列挙を開始します。</summary>
        /// <param name="scope">リソースのスコープ。</param>
        /// <param name="type">リソースの種類。<paramref name="scope"/> が <see cref="ResourceScope.Globalnet"/> の場合にのみこのパラメータを使用します。</param>
        /// <param name="usage">リソースの用途。
        /// <remarks>
        /// 列挙したいコンテナを指定する 構造体へのポインタを指定します。<paramref name="scope"/> が <see cref="ResourceScope.Globalnet"/> でない場合、このパラメータは null でなければなりません。
        /// このパラメータが null の場合、ネットワークのルートが想定されます。（システムはネットワークを階層形式に編成しています。ルートとは、ネットワークの最上位コンテナを意味します。）
        /// このパラメータが null でない場合、NetResource 構造体を指さなければなりません。この構造体は、アプリケーション側で値を書き込んだものでも、<see cref="WNetEnumResource"/> 関数が返したものでもかまいません。
        /// <see cref="NetResource"/> 構造体は、コンテナリソースを指定しなければなりません。つまり、usage パラメータで <see cref="ResourceUsage.Container"/> 値を指定しなければなりません。
        /// すべてのネットワークリソースを列挙するには、アプリケーションは <paramref name="netResource"/> パラメータに null を指定して <see cref="WNetOpenEnum"/> 関数を呼び出し、
        /// 返されたハンドルを <see cref="WNetEnumResource"/> 関数に渡してリソースを列挙します。
        /// <see cref="WNetEnumResource"/> 関数が返した <see cref="NetResource"/> 配列のリソースの中にコンテナリソースが含まれている場合、その構造体を指定して <see cref="WNetOpenEnum"/> 関数を呼び出し、
        /// そのリソースを開いてさらに列挙を行います。
        /// </remarks>
        /// </param>
        /// <param name="netResource">リソースの構造体。</param>
        /// <param name="enumHandle">列挙ハンドラ。</param>
        /// <returns><see cref="WNetConnectionResult"/></returns>
        [DllImport("mpr.dll", CharSet = CharSet.Auto)]
        [SuppressMessage("Microsoft.Interoperability", "CA1401:PInvokesShouldNotBeVisible")]
        [CLSCompliant(false)]
        public static extern WNetConnectionResult WNetOpenEnum(ResourceScope scope, ResourceType type, ResourceUsage usage, [In, MarshalAs(UnmanagedType.AsAny)]object netResource, out IntPtr enumHandle);

        /// <summary>ネットワークリソースの列挙を終了します。</summary>
        /// <param name="EnumHandle">列挙ハンドラ。</param>
        /// <returns><see cref="WNetConnectionResult"/></returns>
        [DllImport("mpr.dll", CharSet = CharSet.Auto)]
        [SuppressMessage("Microsoft.Interoperability", "CA1401:PInvokesShouldNotBeVisible")]
        [CLSCompliant(false)]
        public static extern WNetConnectionResult WNetCloseEnum(IntPtr EnumHandle);

        /// <summary>ネットワークリソースの列挙を継続します。</summary>
        /// <param name="enumHandle">列挙ハンドラ。</param>
        /// <param name="count">列挙したいエントリ数。-1を指定すると、すべてのエントリを列挙します。</param>
        /// <param name="buffer">列挙の結果を受け取る <see cref="NetResource"/> 構造体のバッファ。</param>
        /// <param name="bufferSize">バッファのサイズ（バイト単位）。バッファのサイズが小さすぎて1つのエントリも格納できなかったときは、このパラメータは、必要なバッファのサイズを受け取ります。</param>
        /// <returns><see cref="WNetConnectionResult"/></returns>
        [DllImport("mpr.dll", CharSet = CharSet.Auto)]
        [SuppressMessage("Microsoft.Interoperability", "CA1401:PInvokesShouldNotBeVisible")]
        [CLSCompliant(false)]
        public static extern WNetConnectionResult WNetEnumResource([In]IntPtr enumHandle, [In, Out]ref int count, [Out]IntPtr buffer, [In, Out]ref int bufferSize);
    }
}
